#ifndef VEHICLEPATH_H_
#define VEHICLEPATH_H_

#include <stdlib.h>
#include "edgeSol.h"

/**il valore di ritorno della funzione removeEdgeFromVehiclePath() nel caso in cui l'arco passato come parametro non e' stato
 * trovato nel percorso*/
#define EDGE_NOT_FOUND -2
/**il valore di ritorno della funzione removeEdgeFromVehiclePath() nel caso in cui l'arco passato come parametro e' stato rimosso
 * dal percorso*/
#define EDGE_REMOVED -1
/**il valore di ritorno della funzione getEdgeWalkedTimesInVehiclePath in caso l'arco non sia stato percorso*/
#define NOT_PASSED 0
/**macro da utilizzare in resetMemory e getXXXEdgeIDInVehiclePath */
#define DIRECTION_NEXT 1
/**macro da utilizzare in resetMemory e getXXXEdgeIDInVehiclePath */
#define DIRECTION_PREV 0

/**rappresenta un percorso di un camion. Strutturalmente il percorso e' una lista circolare a doppio puntatore
 * con sentinella. */
typedef struct VehiclePath {
	/**indica l'elemento precedente a questo nella lista PvehiclePath*/
	struct VehiclePath* prev;
	/**indica l'elemento successivo a questo nella lista PvehiclePath*/
	struct VehiclePath* next;
	/**un puntatore all'arco percorso dal camion*/
	PedgeSol edge;
} VehiclePath;

/**indica una lista di VechiclePath: una variabile di questo tipo rappresenta il percorso di un singolo camion k*/
typedef VehiclePath* PvehiclePath;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~COSTRUTTORI~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**funzione di <b>UTILITY: NON UTILIZZARE!!!</b><br>
 *istanzia un vehicle path inserendo i dati nella lista a doppio puntatore in modo grezzo
 *
 * @param _prev l'elemento VehiclePath precedente a questo
 * @param _edge l'edge su cui transita il camion
 * @param _next l'elemento VehiclePath successivo a questo
 * @return un puntatore ad una istanza PvehiclePath
 */
PvehiclePath initVehiclePathCustomized(PvehiclePath _prev, PedgeSol _edge, PvehiclePath _next);

/**costurisce un nuovo percorso di un camion perfettamente vuoto.
 * In realta', essendo questo struttura fondamentalmente una lista circolare a doppio puntatore con sentinella,
 * la lista ha un'unico oggetto che e' appunto la sentinella stessa.
 * @return un puntatore ad una lista di VehiclePath
 */
PvehiclePath initVehiclePath();

/**libera la memoria da una singola istanza di VehiclePath: sia i suoi successori che i suoi predecessori <b>NON</b>
 * verranno eliminati; neppure l'EdgeSol puntato dalla struttura verra' disposto
 *
 * @param path il VehiclePath da deallocare
 */
void freeVehiclePath(PvehiclePath path);

/**libera la memoria dall'istanza path. Verranno eliminate:
 * \li tutti gli elementi successivi a path (path incluso)
 * \li gli edgeSol puntati dai successori di path (path incluso)
 *
 * \pre
 *  \li path non NULL
 * @param path il cammino da eliminare
 */
void freeVehiclePathHard(PvehiclePath path);

/**elimina dalla memoria la lista dei successori di path, <b>senza</b> tuttavia eliminare dalla memoria gli edgeSol ad essi
 * collegati. Utile se la lista da eliminare e' un surrogato di un cammino principale
 * \pre
 *  \li path non NULL
 *
 * @param path il cammino da deallocare
 */
void freeVehiclePathLight(PvehiclePath path);

/**genera una nuova istanza di VehiclePath allocata in memoria uguale a quyella passata. Vengono copiate:
 *  \li la singola istanza di path;
 *
 * cio' significa che i successori e i predecessori di questo path <b>NON</b> vengono copiati. La tabella mostra
 * quali attributi vengono copiati in quale modo:
 * <table>
 *  <tr>
 * 		<th>Campo</th>
 * 		<th>copia per...</th>
 * 	</tr>
 * 	<tr>
 * 		<td>prev</td>
 * 		<td>indirizzo</td>
 * 	</tr>
 * 	<tr>
 * 		<th>next</th>
 * 		<th>indirizzo</th>
 * 	</tr>
 * 	<tr>
 * 		<th>edge</th>
 * 		<th>valore</th>
 * 	</tr>
 * </table>
 *
 * \pre
 *  \li path non NULL
 * \post
 *  \li una nuova istanza in memoria di path. Da deallocare manualmente
 *
 * @param path il singolo path da copiare fisicamente
 * @return un nuova istanza di VehiclePath
 */
PvehiclePath cloneVehiclePath(PvehiclePath path);

/**genera una nuova istanza di VehiclePath allocata in memoria uguale a quella passata. Vengono copiate:
 * \li l'istanza puntata da path
 * \li tutte le istanza che si configurano come i successori a path;
 * \li tutte le edgeSol puntate da ogni singola istanza di VehiclePath;
 *
 * La tabella mostra quali attributi vengono copiati in che modo:
 * <table>
 * 	<tr>
 * 		<th>Campo</th>
 * 		<th>copia per...</th>
 * 	</tr>
 * 	<tr>
 * 		<tr>prev</tr>
 * 		<tr>calcolata di nuovo</tr>
 * 	</tr>
 * 	<tr>
 * 		<th>next</th>
 * 		<th>calcolata di nuovo</th>
 * 	</tr>
 * 	<tr>
 * 		<th>edge</th>
 * 		<th>fisicamente</th>
 * 	</tr>
 * </table>
 *
 * \pre
 *  \li path non NULL
 *
 * \post
 *  \li una nuova lista di vehiclePath uguale in tutto per tutto all'originale
 *
 * @param path il percorso da copiare
 * @return un puntatore ad una istanza di lista di VehiclePath
 */
PvehiclePath cloneVehiclePathHard(PvehiclePath path);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~OPERAZIONI~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**aggiunge un nuovo arco percorso da un camion all'interno della lista passata come parametro. L'arco viene aggiunto
 * in coda alla lista. In caso l'arco esista gia' all'interno del percorso, viene incrementato il campo x del relativo EdgeID.
 *
 *  \pre
 *   \li edge non NULL
 *   \li edge ha i<j
 *   \li pvp non NULL
 *	\post
 *	 \li l'arco passato e' all'interno della lista
 *
 * @param edge indica l'arco da aggiungere in lista
 * @param path indica la lista che deve essere aggiornata
 * @return TRUE se l'arco e' stato aggiunto fisicamente al percorso, FALSE se era gia' contenuto in esso
 */
bool addEdgeToVehiclePath(PedgeID pid, PvehiclePath pvp);

/** aggiunge l'edgeSol passato come parametro come nuovo arco percorso all'interno del cammino passato.
 * <b>Non vengono effettuate copie dell'EdgeSol</b>; inoltree nessun controllo viene
 * effettuato qualor al'arco sia gia' presente nella lista
 *
 * \pre
 *  \li path non NULL
 *  \li path inizializzato correttamente
 * \post
 *  \li una nuova istanza di una lista di archi contenuta in memoria puntante l'edgeSol passato
 *
 *
 * @param pvp il cammino in cui agigungere la nuova soluzione
 * @param e l'edgeSol da aggiungere
 */
void addEdgeSolInVehiclePathCustomized(PvehiclePath pvp,PedgeSol e);

/**rimuove UNA percorrenza dell'arco specificato dal percorso del camion. Esistono varie casistiche:
 * \li l'arco viene transitato dal camion piu' di 1 volta: in questo caso viene decrementato il campo x dell'EdgeSol
 * \li l'arco viene transitato dal camion una sola volta: in questo caso l'arco viene rimosso dal percorso
 * \li l'arco non viene mai trasitato dal camion: la funzione non effettua alcuna operazione.
 *
 * \pre
 *  \li edge non NULL
 *  \li pvp non NULL
 *  \li edge ha i<j
 *
 *
 * @param edge l'arco da rimuovere
 * @param path il percorso da controllare
 * @return esistono diversi casi:
 * 	\li EDGE_REMOVED se l'arco e' stato rimosso dal percorso
 * 	\li EDGE_NOT_FOUND se l'arco edge non era incluso nel percorso
 * 	\li il numero di volte (strettamente positive) che l'arco edge viene percorso dopo aver eseguito questa funzione
 */
int removeEdgeFromVehiclePath(PedgeID pid, PvehiclePath pvp);

/**cancella completamente l'arco specificato dal percorso del camion senza curarsi di quante volte
 * il camion e' passato per l'arco.
 *
 * \pre
 *  \li edge non NULL
 *  \li pvp non NULL
 *  \li edge ha i<j
 *
 * @param edge l'arco da rimuovere
 * @param path il percorso da controllare
 * @return TRUE se è stato eliminato; FALSE se non esisteva.
 */
bool deleteEdgeFromVehiclePath(PedgeID pid, PvehiclePath pvp);

/**sincronizza la memoria interna con il percorso passato come parametro. E' <b>necessario</b> chiamare questa funzione
 * prima della prima chiamata di una delle funzioni:
 * \li getPrevEdgeInVehiclePath();
 * \li getNextEdgeInVehiclePath();
 * \li getNearEdgeInVehiclePath();
 * o comunque dopo aver terminato di usare le funzioni precedentemente elencato in un ciclo.<br>
 * Supponiamo infatti di aver appena concluso di analizzare un percorso; se vogliamo analizzare un secondo percorso (eventualmente
 * diverso dal primo) basta richiamare questa funzione usando l'invocazione:<br>
 * <em>
 *  while ((edge=getNextEdgeInVehiclePath(percorso_camion_1))!=NULL){<br>
 *  	//CODE
 *  }<br>
 *  resetMemory(percorso_camion_2);<br>
 *  while ((edge=getNextEdgeInVehiclePath(percorso_camion_2))!=NULL){<br>
 *  	//OTHER CODE
 *  }<br>
 * </em>
 * questa funzione non puo' essere richiamata all'interno di un ciclo che e' gia' governato da anche una sola delle funzione sopra elencate
 *
 * @param path indica il percorso da settare
 * @param direction indica la direzione da cui partire: puo' valere DIRECTION_NEXT o DIRECTION_PREV
 */
void resetMemory(PvehiclePath path, int direction);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ QUERY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**verifica se il percorso effettuato dal particolare camion transita o meno dal particolare arco.
 *
 * @param edge l'edge da trovare
 * @param path il percorso da analizzare
 * @return la struttura di tipo VehiclePath (quindi comprende anche successori e predecessori) che contiene l'arco trovato. NULL se l'arco
 * non viene percorso.
 */
PedgeSol getEdgeWalkedInVehiclePath(PedgeID pe, PvehiclePath path);

/**restituisce il numero di percorrenze del particolare arco nel particolare percorso.
 *
 * @param edge l'edge da trovare
 * @param path il percorso da analizzare
 * @return il valore x dell'arco nel percorso. NULL se l'arco non viene percorso.
 */
int getEdgeWalkedTimesInVehiclePath(PedgeID p_edge, PvehiclePath p_path);

/**
 * @param p_path il percorso in esame
 * @param N cardinalità del grafo. Permette una computazione molto rapida della procedura
 * @return un array di *setLength identificativi dei nodi toccati dal path. */
int* getNodeSetTouchedInVehiclePath(PvehiclePath p_path, int N, int* setLength);

/**
 * @return vero sse l'arco è percorso una e una sola volta nel path.
 */
bool isEdgeWalkedOnceInVehiclePath(PedgeID p_edge, PvehiclePath p_path);

/**la funzione calcola se l'arco passato e' presente o meno nel cammino. La funzione non altera in alcun modo la memoria
 * quindi e' perfettamente compatibile con le funzioni:
 * \li getPrevEdgeInVehiclePath;
 * \li getNextEdgeInVehiclePath;
 * \li getNearEdgeInVehiclePath.
 * Non e' dunque necessario richiamare resetMemory prima o dopo averla utilizzata.
 *
 * Nella pratica wrappa la funzione getEdgeWalkedInVehiclePath.
 *
 * @param path il percorso da analizzare
 * @return TRUE se l'arco e' compreso nel percorso, FALSE altrimenti
 */
bool isEdgeWalkedInVehiclePath(PedgeID p_edge, PvehiclePath p_path);

/**ad ogni richiamo della funzione viene tornato un arco all'interno del percorso passato come parametro. Quando il percorso e' terminato
 * la funzione ritorna NULL. Prima di utilizzare questa funzione assicurarsi di richiamare sempre
 * la funzione resetMemory: il mancato richiamo portera' a comportamenti imprevedibili. Una volta che il percorso e' terminato
 * <b>utilizzare la funzione resetMemory</b> prima di riutilizzare questa funzione.<br>
 * UTILIZZO<br>
 * <em>
 * resetMemory(percorso_camion_1);<br>
 * while (edge=getNextEdgeInVehiclePath(percorso_camion_1)){<br>
 * 	//PUT YOUR CODE HERE...<br>
 * }<br>
 * </em>
 *
 * @param path il path che si sta percorrendo
 * @return il prossimo arco nel percorso, NULL se siamo arrivati alla fine del percorso
 */
PedgeSol getNextEdgeInVehiclePath(PvehiclePath p_path);

/**ad ogni richiamo della funzione viene tornato un arco all'interno del percorso passato come parametro. Quando il percorso e' terminato
 * la funzione ritorna NULL. Prima di utilizzare questa funzione assicurarsi di richiamare sempre
 * la funzione resetMemory: il mancato richiamo portera' a comportamenti imprevedibili. Una volta che il percorso e' terminato
 * <b>utilizzare la funzione resetMemory</b> prima di riutilizzare questa funzione.<br>
 * UTILIZZO<br>
 * <em>
 * resetMemory(percorso_camion_1);<br>
 * while ((edge=getNextEdgeInVehiclePath(percorso_camion_1))!=NULL){<br>
 * 	//PUT YOUR CODE HERE...<br>
 * }<br>
 * </em>
 *
 * @param path il path che si sta percorrendo
 * @return l'arco precedente all'ultimo arco ritornato da questa funzione nel percorso, NULL se siamo arrivati alla fine del percorso
 */
PedgeSol getPrevEdgeInVehiclePath(PvehiclePath path);

/**ad ogni richiamo della funzione viene tornato un arco all'interno del percorso passato come parametro. Quando il percorso e' terminato
 * la funzione ritorna NULL. Prima di utilizzare questa funzione assicurarsi di richiamare sempre
 * la funzione resetMemory: il mancato richiamo portera' a comportamenti imprevedibili. Una volta che il percorso e' terminato
 * <b>utilizzare la funzione resetMemory</b> prima di riutilizzare questa funzione.<br>
 * UTILIZZO<br>
 * <em>
 * resetMemory(percorso_camion_1);<br>
 * while ((edge=getNextEdgeInVehiclePath(percorso_camion_1))!=NULL){<br>
 * 	//PUT YOUR CODE HERE...<br>
 * }<br>
 * </em>
 *
 * @param path il path che si sta percorrendo
 * @param direction la direzione da scliegere per ottenere il prossimo arco del percorso. puo' assumere due valori diversi:
 * 	\li DIRECTION_NEXT per scegliere l'arco posteriore a quello corrente
 * 	\li DIRECTION_PREV per scegliere l'arco precedente a quello corrente
 * @return l'arco precedente all'ultimo arco ritornato da questa funzione nel percorso, NULL se siamo arrivati alla fine del percorso
 */
PedgeSol getNearEdgeInVehiclePath(PvehiclePath path, int direction);

/** @param path il percorso in analisi
 *  @param v l'indice del nodo sotto esame
 *  @param N la cardinalità del grafo
 *  @return TRUE sse il nodo v è contenuto nel percorso path
 */
bool isNodeTouchedInVehiclePath(PvehiclePath path, int v);

/**determina gli archi che sono adiacenti al nodo passato all'interno del percorso. Per esempio
 * la funzione applicata al percorso (1;2)(2;3)(3;4)(4;5)(5:3)(3;6)(6;1) con nodo 3 ritornera'
 * il set di archi (2;3)(3;4)(3;5)
 *
 * \pre
 *  \li path non NULL
 * \post
 *  \li un'istanza di vehiclePath contenente tutti gli archi toccanti il dato nodo. <b>RIcordarsi</b> di disporre di questa istanza!
 *
 *
 * @param path il percorso da valutare
 * @param node il nodo in comune a tutti gli archi
 * @return una lista di archi che toccano il nodo passato
 */
PvehiclePath getEdgesNearNodeInVehiclePath(PvehiclePath path, int node);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~STAMPE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** stampa il percorso effettuato
 *
 * @param f file su cui scrivere il percorso
 * @param path percorso da stampare
 */
void printVehiclePath(FILE* f, PvehiclePath path);

#endif /* VEHICLEPATH_H_ */
